# -*- coding: utf-8 -*-
from memoriaFisica.MemoriaFisica import MemoriaFisica
import threading

class MMU():
    #INICIALIZACION
    lock = threading.RLock() # semaforo

    ###constructor
    def  __init__(self, asignador):
        self.io = None
        self.memoriaFisica = MemoriaFisica (15)
        self.asignador = asignador
        self.asignador.setMMU (self)
        self.tablaPcbBase = {}
        
###############################################################################################################

    #METODOS        
    def loadProgram (self, pcb):
        print('load program', pcb.getProgram().getName())
        bloque = self.asignador.realizarAsignacion(pcb.getProgram())
        direccion = bloque.getDirInicio()
        self.tablaPcbBase[pcb] = direccion
        self.putProgram (pcb.getProgram(), direccion)

    def memoriaContienePCB (self, pcb):
        encontrePCB = False
        for k in self.tablaPcbBase.keys():
            if (k == pcb):
                encontrePCB = True
        return encontrePCB
    
    def get(self, pcb):
        self.lock.acquire() # adquiero el semaforo, para evitar problemas en la ejecucion
        try:
            return self.getAux(pcb)
        finally:                                         
            self.lock.release() # libero el semaforo 
            
    def getAux (self, pcb):
        if not self.memoriaContienePCB(pcb): # si no se encuentra en memoria, esta en disco 
            self.asignador.io.eliminar(pcb.getProgram())
            self.asignador.realizarAsignacion(pcb.getProgram())#y le vuelvo asignar memoria para poder ejecutarlo
        direccion= self.tablaPcbBase[pcb]+ pcb.getCurrentInstruction()
        result = self.memoriaFisica.get(direccion)
        return result
   
    def unload (self, pcb):
        direccion = self.tablaPcbBase[pcb]
        self.limpiarBloque(self.asignador.eliminarBloqueOcupado(direccion))
        del self.tablaPcbBase[pcb]

    def ponerListo(self,temporal):
        self.asignador.realizarAsignacion(temporal.getProgram())

            

    def limpiarBloque (self, bloque):
        i = bloque.getDirInicio()
        while i < bloque.getDirFin():
            self.memoriaFisica.put (None, i)
            i += 1
        
    def putProgram (self, program, dirInicio):
        for intr in program.getCodigo():
            self.memoriaFisica.put (intr, dirInicio)
            dirInicio += 1
                
    
    def setIO(self, io):
        self.io = io
        self.asignador.setIO(io)